小明收到需求, 需求如下:
麥當雞系統需要統計消費次數的報表, 報表內容需要列出每一種消費種類的消費次數.
麥當雞系統中有一個消費種類Enum 叫做ChargeType
public enum ChargeType
{
DuckNuggets,
ChickenNuggets,
FrenchFries,
FriedChickenChops,
GreenBeanSoup
}
小明寫了統計方法
public ChargeStatistics Compute(ChargeType[] chargeHistory)
{
var data = new ChargeStatistics();
foreach (var r in chargeHistory)
{
if (r == ChargeType.DuckNuggets)
data.DuckNuggets++;
else if (r == ChargeType.ChickenNuggets)
data.ChickenNuggets++;
else if (r == ChargeType.FrenchFries)
data.FrenchFries++;
else if (r == ChargeType.FriedChickenChops)
data.FriedChickenChops++;
else if (r == ChargeType.GreenBeanSoup)
data.GreenBeanSoup++;
}
return data;
}
觀察上述的程式碼, 可以發現到
設計守則 如果你有大量的資料型別的資料, 就考慮可能將資料組織起來,形成一個物件類.
集合資料的方法有很多種, 資料結構可以用陣列也可以利用集合(List/Dictionary/...).
故統計的結果物件可以修改為
public class ChargeStatistics
{
public Dictionary<ChargeType, int> Data { get; set; }
}
然後在統計方法內改寫為
public ChargeStatistics Compute(ChargeType[] chargeHistory)
{
var result = new ChargeStatistics();
foreach (var r in chargeHistory)
{
IncreaseCounter(result.Data, r);
}
return result;
}
private void IncreaseCounter(Dictionary<ChargeType, int> data, ChargeType chargeType)
{
if (!data.TryGetValue(r, out var counter))
{
data[r] = 1;
}
else
{
data[r] = counter + 1;
}
}
我們可以直接使用Dictionary 字典的特性, 來統計計算每一種消費種類的次數.
在IncreaseCounter 方法中, 檢查data 是否出現了某個ChargeType ,
在整理資料的時候常常都需要給資料做分組, 以便更進一步的分析及處理,
而C# 有提供分組統計的方法, 我們可以拿來利用.
我們可以利用LINQ Group 語法將chargeHistory 資料做分組, 然後再用Count() 方法統計次數
故Compute() 方法可以改寫為
public ChargeStatistics Compute(ChargeType[] chargeHistory)
{
var result = new ChargeStatistics();
var q1 = from tb1 in chargeHistory
group tb1 by tb1 into g1
select new
{
Key = g1.Key,
Count = g1.Count()
};
result.Data = q1.ToDictionary(x => x.Key, x => x.Count);
return result;
}
當然假如你不喜歡這種長得有點像SQL 語法的運算式, 你也能改寫為Linq Method
public ChargeStatistics Compute(ChargeType[] chargeHistory)
{
var result = new ChargeStatistics();
var q1 = chargeHistory.GroupBy(x => x)
.Select(new
{
Key = g1.Key,
Count = g1.Count()
});
result.Data = q1.ToDictionary(x => x.Key, x => x.Count);
return result;
}
最後在這個 "統計結果物件" 這個地方, Data 屬性的宣告有點模糊,
public class ChargeStatistics
{
public Dictionary<ChargeType, int> Data { get; set; }
}
對於不熟悉麥當雞系統的維護人員可能會不知道這個 Dictionary<ChargeType, int> 裡面的 int 代表的是甚麼意思.
故我們可以新增一個物件來明確宣告 "一個 ChargeType 的統計資料"
public class ChargeTypeStatistic
{
public ChargeType ChargeType { get; set; }
public int Count { get; set; }
}
然後宣告Data 屬性為List ,
這樣就可以明確讓維護人員知道這個Data 的定義
public class ChargeStatistics
{
public List<ChargeTypeStatistic> Data { get; set; }
}
當然統計方法也要修改為下面方式
public ChargeStatistics Compute(ChargeType[] chargeHistory)
{
var result = new ChargeStatistics();
result.Data = chargeHistory.GroupBy(x => x)
.Select(new ChargeTypeStatistic
{
ChargeType = g1.Key,
Count = g1.Count()
})
.List();
return result;
}
如此一來維護人員也比較清楚知道統計結果物件裡面的代表意義,
對程式碼的理解將不必再依靠繁雜的註解和厚厚的文件.